<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<script>
			// 缓存到内存
			function memoizeFunction(func) {
				var cache = {};
				return function() {
					var key = arguments[0];
					if (cache[key]) {
						console.log(cache, 'cache2')
						return cache[key];
					} else {
						var val = func.apply(this, arguments);
						cache[key] = val;
						console.log(cache, 'cache1')
						return val;
					}
				};
			}
			var fn = function(n) {
				// 1，1，2，3，5，8，13，21，34，55，89，144……
				/**
				 * f5 = f3 + f4
				 *    = f1 + f2 + f2 + f3
				 *    = f1 + f0 + f1 + f0 + f1 + f1 + f2
				 *    = f1 + f0 + f1 + f0 + f1 + f1 + f0 + f1
				 *    = 5
				 */
				// console.log(n, 'n')
				return (n === 0 || n === 1) ? n : fn(n - 1) + fn(n - 2);
			}
			console.time('缓存运算时间')
			var fnCache = memoizeFunction(function(n) {
				// console.log(n, 'n')
				return (n === 0 || n === 1) ? n : fnCache(n - 1) + fnCache(n - 2);
			});
			fnCache(5)
			// console.log(fnCache(5), 'fnCache')
			console.timeEnd('缓存运算时间')

			{
				function getClimbingWays(n) {
					if (n < 1) {
						return 0;
					}
					if (n === 1) {
						return 1;
					}
					if (n === 2) {
						return 2;
					}
					return getClimbingWays(n - 1) + getClimbingWays(n - 2);
				}
				console.time('运算时间')
				getClimbingWays(40)
				console.timeEnd('运算时间')
			}

			{
				let map = new Map();

				function getClimbingWays(n) {
					if (n < 1) {
						return 0;
					}
					if (n === 1) {
						return 1;
					}
					if (n === 2) {
						return 2;
					}
					if (map.has(n)) {
						return map.get(n);
					} else {
						let value = getClimbingWays(n - 1) + getClimbingWays(n - 2);
						map.set(n, value);
						return value;
					}
				}
				console.time('运算时间2')
				getClimbingWays(5000)
				console.timeEnd('运算时间2')
			}

			{
				function getClimbingWays(n) {
					if (n < 1) {
						return 0;
					}
					if (n === 1) {
						return 1;
					}
					if (n === 2) {
						return 2;
					}
					let a = 1,
						b = 2,
						temp = 0;
					for (let i = 3; i <= n; i++) {
						temp = a + b;
						a = b;
						b = temp;
					}
					return temp;
				}
				console.time('运算时间3')
				getClimbingWays(5000)
				console.timeEnd('运算时间3')
			}

			{
				function getClimbingWays(n) {
					if (n <= 1) return 1
					return getClimbingWays(n - 1) + getClimbingWays(n - 2)
				}
				console.time('运算时间4')
				getClimbingWays(40)
				console.timeEnd('运算时间4')
			}

			{
				function getClimbingWays(n, val1 = 1, val2 = 1) {
					if (n <= 1) return val2
					return getClimbingWays(n - 1, val2, val1 + val2)
				}
				console.time('运算时间5')
				getClimbingWays(40)
				console.timeEnd('运算时间5')
			}

			{
				function factorial(n) {
					if (n === 1) return 1
					return n * factorial(n - 1)
				}
				console.time('阶乘时间')
				factorial(5)
				console.timeEnd('阶乘时间')
			}

			{
				function factorial(n, total = 1) {
					if (n === 1) return total
					return factorial(n - 1, n * total)
				}
				console.time('阶乘时间2')
				factorial(5)
				console.timeEnd('阶乘时间2')
			}

			{
				function tailFactorial(n, total) {
					if (n === 1) return total
					return tailFactorial(n - 1, n * total)
				}
				function factorial(n) {
					return tailFactorial(n, 1)
				}
				console.time('阶乘时间3')
				factorial(5)
				console.timeEnd('阶乘时间3')
			}

			{
				function tailFactorial(n, total) {
					if (n === 1) return total
					return tailFactorial(n - 1, n * total)
				}
				function currying(fn, n) {
					return function(m) {
						return fn.call(this, m, n)
					}
				}
				const factorial = currying(tailFactorial, 1)
				console.time('阶乘时间4')
				factorial(5)
				console.timeEnd('阶乘时间4')
			}

			// const price = {
			// 	obj: {
			// 		full50(money) {
			// 			return money - 5
			// 		},
			// 		full100(money) {
			// 			return money - 10
			// 		}
			// 	},
			// 	getPrice(type, money) {
			// 		return this.obj[type] ? this.obj[type](money) : money
			// 	},
			// 	addPrice(type, youhui) {
			// 		this.obj[type] = function(money) {
			// 			return money - youhui
			// 		}
			// 	}
			// }
			// price.addPrice('full500', 50)
			// console.log(price.getPrice('full1', 1))
			// console.log(price.getPrice('full50', 50))
			// console.log(price.getPrice('full100', 100))
			// console.log(price.getPrice('full500', 500))		
			class Price {
				constructor(money) {
					this.obj = {
						full50(money) {
							return money - 5
						},
						full100(money) {
							return money - 10
						}
					}
				}
				getPrice(type, money) {
					return this.obj[type] ? this.obj[type](money) : money
				}
				addPrice(type, youhui) {
					this.obj[type] = function(money) {
						return money - youhui
					}
				}
			}
			const price = new Price()
			price.addPrice('full500', 50)
			// console.log(price.getPrice('full1', 1)) // 1
			// console.log(price.getPrice('full50', 50)) // 45
			// console.log(price.getPrice('full100', 100)) // 90
			// console.log(price.getPrice('full500', 500))	// 450
		</script>
	</body>
</html>